#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <unordered_map>
#include <memory>
#include <thread>
#include <unistd.h>

using TaskFunc = std::function<void()>;
using ReleaserFunc = std::function<void()>;

// 定时器任务
class TimerTask{
public:
    TimerTask(uint64_t id, uint32_t delay, const TaskFunc& cb, int start_tick = 0):
    _id(id),
    _timeout(delay),
    _cb(cb),
    _start_tick(start_tick),
    _canceled(false)
    {}

    ~TimerTask() { 
        if (!_canceled) {
            std::thread(_cb).detach(); // 异步执行
        }
        // if (!_canceled) _cb();  // 用这个的话 _cb 就会先执行, 否则后执行
        _release(); 
    }

    void SetReleaser(const ReleaserFunc& release){_release = release;}
    ReleaserFunc GetReleaser() const{return _release;}
    uint64_t GetId() const {return _id;}
    void Cancel() {_canceled = true;} // 取消定时任务
    uint32_t GetDelayTime() const { return _timeout; }

    int GetStartTick() const { return _start_tick; }
    void SetStartTick(int tick) { _start_tick = tick; } // 设置定时器任务的起始 tick

private:
    int _start_tick; // 记录定时器任务的起始 tick
    uint64_t _id;           // 定时器任务 id
    uint32_t _timeout;      // 定时任务超时时间
    bool _canceled;         // 是否取消定时任务(true: 取消)
    TaskFunc _cb;           // 定时器对象要执行的定时任务
    ReleaserFunc _release;  // 用于删除 TimerWheel 中保存的定时器对象信息
};

// 定时器轮
class TimerWheel{
private:
    using WeakTask = std::weak_ptr<TimerTask>; // 辅助 shared_ptr 解决循环引用问题
    using PtrTask = std::shared_ptr<TimerTask>;
public:
    TimerWheel(int capacity = 60):
    _capacity(capacity),
    _tick(0)
    {
        _wheel.resize(_capacity);
    }

    // 1. 添加定时任务
    void AddTimer(uint64_t id, uint32_t delay, const TaskFunc& cb){  
        if (delay > _capacity) {
            std::cerr << "Timer delay exceeds capacity" << std::endl;
            return;
        }
        PtrTask pt(new TimerTask(id, delay, cb, _tick));
        pt->SetReleaser(std::bind(&TimerWheel::RemoveTimer, this, id));
        
        int pos = (_tick + delay) % _capacity; // 计算定时器任务在轮子上的位置
        _wheel[pos].push_back(pt); // 将定时器任务添加到轮子上
        _timers[id] = WeakTask(pt); // 不能用 shared_ptr, 否则永久有shared_ptr 来管理, 计数不归0         
    }   
    
    // 2. 删除定时任务
    void RemoveTimer(uint64_t id){
        auto it = _timers.find(id);
        if(it == _timers.end()) return ;
        _timers.erase(it);
    }
    // 3. 执行定时任务 
    void RunTimerTask(){
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear(); // 清空当前 tick 的任务
    }

    // 4. 刷新/延迟 定时任务
    void RefreshTimer(uint64_t id) {
        // 1, 通过保存定时器对象的 weak_ptr 来获取定时器对象 添加到轮子中
        auto it = _timers.find(id);
        if (it == _timers.end())  // 没找到定时任务, 无法刷新和延迟
            return;
        
        PtrTask pt = it->second.lock(); // lock获取weak_ptr管理的对象对应的shared_ptr
        if (!pt) return;
	
        // 方法1：下面两行处理的刷新之后定时时间也重新计时
        int remaining = pt->GetDelayTime();
        
        // 由于上面这里的刷新把延迟时间也会重新计算, 因此任务原定5秒后执行，已过去3秒，刷新后仍按5秒计算，导致实际延迟8秒
        // 解决办法: 记录起始 tick
        
        // // 方法2：刷新不延迟计时
        // // 计算剩余时间 = 原始延迟 - (当前 tick - 起始 tick)
        // int elapsed = (_tick - pt->GetStartTick() + _capacity) % _capacity; // 防止负数
        // int remaining = pt->GetDelayTime() - elapsed;
        // remaining = std::max(remaining, 1); // 确保至少延迟1秒
        // // 更新任务的起始 tick 为当前 tick
        // pt->SetStartTick(_tick);

        int pos = (_tick + remaining) % _capacity;
        _wheel[pos].push_back(pt);
    }

    // 5. 取消定时任务
    void CancelTimer(uint64_t id) {
        auto it = _timers.find(id);
        if(it == _timers.end()) return ;

        PtrTask pt = it->second.lock(); // lock获取weak_ptr管理的对象对应的shared_ptr
        // 如果weak_ptr管理的对象已经被销毁（即引用计数为0），lock()会返回一个空的shared_ptr
        // 如果对象仍然存在，lock()会返回一个有效的shared_ptr，指向该对象

        if(pt) pt->Cancel(); // 取消定时任务
    }
private:
    int _tick; // 当前指针, 走到哪释放哪(相当于执行哪里任务)
    int _capacity; // 定时器轮的大小 -- 最大延迟时间
    std::vector<std::vector<PtrTask>> _wheel; // 定时器轮
    std::unordered_map<uint64_t, WeakTask> _timers; // 定时器任务 id 和定时器对象的映射关系
};

struct Test{
    Test(){std::cout << "构造" << std::endl;}
    ~Test(){std::cout << "析构" << std::endl;}
};

void DelTest(Test *t){
    std::cout << "删除" << std::endl;
    delete t;
    t = nullptr; 
}

int main() {
    TimerWheel tw(10); // 假设时间轮容量为10

    // 添加一个5秒后执行的任务 -- 保证刷新任务不影响执行
    tw.AddTimer(1, 3, [](){ 
        std::cout << "任务执行时间：" << time(nullptr) << std::endl; 
    });

    // 模拟时间推进（单位：秒）
    for (int i = 0; i < 8; ++i) {
        std::cout << "当前时间：" << time(nullptr) << " tick: " << i << std::endl;
        
        // 在第2秒时刷新任务
        if (i == 2) {
            std::cout << "刷新任务" << std::endl;
            tw.RefreshTimer(1);
        }
        
        sleep(1);
        tw.RunTimerTask();
    }

    std::cout << "------------------" << std::endl;
    Test *t = new Test();
    tw.AddTimer(2,2, std::bind(DelTest, t));
    for(int i = 0; i < 4; i++){
        std::cout << "tick: " << i << " , 刷新定时器任务" << std::endl;
        sleep(1);
        if(i == 1){
            tw.CancelTimer(2); // 取消任务
        }
        tw.RefreshTimer(2); // 刷新定时器任务1
        tw.RunTimerTask(); // 向后移动指针
    }
    return 0;
}